/*
 * ECARX Technology Limited is the owner of the copyright and the trade secret of this software.
 * Without permission, no one has the right to obtain, disclose or use this software in any way.
 */

package com.ecarx.systemui.plugin.controller;

import android.content.Context;
import android.util.Log;

import com.ecarx.module_api.BTController;
import com.ecarx.module_bluetooth.BTConstants;
import com.ecarx.module_bluetooth.aosp.CachedBluetoothDevice;
import com.ecarx.module_bluetooth.base.enums.SwitchStateEnum;
import com.ecarx.module_bluetooth.enums.BtProfileEnums;
import com.ecarx.module_bluetooth.enums.ConnectProfileOptionEnum;
import com.ecarx.module_bluetooth.interfaces.IBTListener;
import com.ecarx.module_bluetooth.interfaces.IBluetoothApi;
import com.ecarx.systemui.plugin.utils.LogUtils;
import com.ecarx.systemui.plugin.PluginContext;

import java.util.ArrayList;
import java.util.List;

public class BluetoothController implements IBTListener<CachedBluetoothDevice> {

    private static final String TAG = "BluetoothController";

    private static BluetoothController bluetoothController;

    public static BluetoothController getInstance() {
        return bluetoothController;
    }

    private IBluetoothApi apiManager;

    private BluetoothController() {
        init();
    }


    public static synchronized void initBluetooth() {
        if (bluetoothController == null) {
            bluetoothController = new BluetoothController();
        }
    }

    private void init() {
        Context hostAppContext = PluginContext.getContextByActThread();
        if (hostAppContext == null) {
            LogUtils.e(TAG, "hostAppContext is null");
            return;
        }
        LogUtils.d(TAG, "initBluetooth...");
        BTController.getInstance().init(hostAppContext);
        apiManager = BTController.getInstance().getApiManager();
        apiManager.registerListener(this);
    }

    public boolean isEnable() {
        if (apiManager == null) {
            LogUtils.e(TAG, "is fail , The apiManager is null");
            return false;
        }
        return apiManager.isEnable();
    }

    public boolean openBlue() {
        boolean enable = isEnable();
        if (enable) {
            LogUtils.e(TAG, " Bluetooth is already enabled");
            return false;
        }
        apiManager.setEnable(true);
        return true;
    }

    public void closeBlue() {
        boolean enable = isEnable();
        if (!enable) {
            LogUtils.e(TAG, "closeBlue is fail , Bluetooth is can not enable");
            return;
        }
        boolean scanning = apiManager.isScanning();
        if (scanning) {
            apiManager.scanStop();
        }
        apiManager.setEnable(false);
    }

    public void scanBluetoothDevices() {
        boolean enable = isEnable();
        if (!enable) {
            LogUtils.e(TAG, "openBlue is fail , Bluetooth is can not enable");
        }
        apiManager.scanStart(false);
    }

    public List<CachedBluetoothDevice> getPairedBtDevices(){
        return apiManager.getPairedBTs();
    }

    public String getBtName(){
        return apiManager.getBtName();
    }

    public void startScanMode(){
        if (isEnable()) {
            apiManager.setScanMode(BTConstants.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
            apiManager.scanStart(true);
            LogUtils.d(TAG, "startScanMode: ");
        }
    }

    public void stopScanMode(){
        apiManager.setScanMode(BTConstants.Config.BT_SCAN_MODE_DEFAULT);
        apiManager.scanStop();
    }

    //---------------------以下是蓝牙回调方法---------------------------------------------------------

    @Override
    public void onStateChanged(SwitchStateEnum switchStateEnum) {
        for (OnBTStateListener onBTStateListener : mOnBTStateListenerList) {
            onBTStateListener.onBtState(switchStateEnum);
        }
        if (mOnBtEnableListener != null && (switchStateEnum == SwitchStateEnum.ON || switchStateEnum == SwitchStateEnum.OFF)) {
            mOnBtEnableListener.onBtEnable(switchStateEnum == SwitchStateEnum.ON);
        }
    }

    @Override
    public void onLocalNameChanged(String btName) {
        for (OnBTStateListener onBTStateListener : mOnBTStateListenerList) {
            onBTStateListener.onBtName(btName);
        }
    }

    private final int SCAN_TRY_COUNT_MAX = 5;
    private int mScanTryCount = 0;
    private boolean isLoading = false;

    @Override
    public void onScanStateChanged(boolean b) {
        LogUtils.d(TAG, "onScanStateChanged() called with: b = [" + b + "]");
        if (!b) {
            mScanTryCount++;
            if (mScanTryCount >= SCAN_TRY_COUNT_MAX) {
                LogUtils.d(TAG, "onScanStateChanged: end!");
                for (OnBTStateListener onBTStateListener : mOnBTStateListenerList) {
                    onBTStateListener.onScanStateChanged(false);
                }
                isLoading = false;
            } else {
                stopScanMode();
                startScanMode();
                LogUtils.d(TAG, "onScanStateChanged: try count=" + mScanTryCount);
            }
        } else {
            if (mScanTryCount == 0 || !isLoading) {
                for (OnBTStateListener onBTStateListener : mOnBTStateListenerList) {
                    onBTStateListener.onScanStateChanged(true);
                }
                isLoading = true;
            }
        }
    }

    public void resetScanTryCount(){
        mScanTryCount = 0;
        isLoading = false;
    }

    private final List<CachedBluetoothDevice> mScanBtDeviceList = new ArrayList<>();

    @Override
    public void onScanFind(CachedBluetoothDevice device) {
        LogUtils.d(TAG,"onScanFind " + device.getName());
        updateScanDevices(device);
    }

    private void updateScanDevices(CachedBluetoothDevice device) {
        if (!apiManager.getPairedBTs().contains(device)) {
            if (!mScanBtDeviceList.contains(device)) {
                mScanBtDeviceList.add(device);
            }
        } else {
            if (mScanBtDeviceList.contains(device)) {
                mScanBtDeviceList.remove(device);
            }
        }
        // 通知 UI 变化
        for (OnBTStateListener onBTStateListener : mOnBTStateListenerList) {
            onBTStateListener.onScanDevices(mScanBtDeviceList);
        }
        LogUtils.d(TAG, "updateScanDevices() called with: mScanBtDeviceList = [" + mScanBtDeviceList + "]");
    }

    public void reverseBtConnectStatus(CachedBluetoothDevice device){
        if (device == null) {
            Log.e(TAG, "reverseBtConnectStatus: device is null");
            return;
        }
        boolean deviceConnected = device.isConnected();
        if (deviceConnected) {
           disconnectDevice(device);
        } else {
            //如果是未连接的，需同时连接 a2dp和hfp
            connectDevice(device);
        }
    }

    public void disconnectDevice(CachedBluetoothDevice device){
        if (device == null) {
            Log.e(TAG, "reverseBtConnectStatus: device is null");
            return;
        }
        boolean deviceConnected = device.isConnected();
        if (deviceConnected) {
            apiManager.disconnect(device, ConnectProfileOptionEnum.MEDIA);
            apiManager.disconnect(device, ConnectProfileOptionEnum.CALL);
            apiManager.disconnect(device, ConnectProfileOptionEnum.ALL);
        }
    }

    public void connectDevice(CachedBluetoothDevice device){
        if (device == null) {
            Log.e(TAG, "reverseBtConnectStatus: device is null");
            return;
        }
        boolean deviceConnected = device.isConnected();
        if (!deviceConnected) {
            apiManager.connect(device, ConnectProfileOptionEnum.MEDIA);
            apiManager.connect(device, ConnectProfileOptionEnum.CALL);
        }
    }

    public void disconnectDevice(CachedBluetoothDevice device, ConnectProfileOptionEnum profile){
        apiManager.disconnect(device, profile);
    }

    public void connectDevice(CachedBluetoothDevice device, ConnectProfileOptionEnum profile){
        apiManager.connect(device, profile);
    }


    @Override
    public void onBondAdded(CachedBluetoothDevice cachedBluetoothDevice) {

    }

    @Override
    public void onBondRemoved(CachedBluetoothDevice cachedBluetoothDevice) {

    }

    @Override
    public void onBondChanged(CachedBluetoothDevice cachedBluetoothDevice, int i) {

    }

    @Override
    public void onBondError(CachedBluetoothDevice cachedBluetoothDevice, int i) {

    }

    @Override
    public void onConnectChanged(CachedBluetoothDevice device) {
        LogUtils.d(TAG, "onConnectChanged() called with: device = [" + device.toString() + "]");
        updateScanDevices(device);
        mOnBtTypeListener.onBtType();
    }

    @Override
    public void onProfileServiceConnectChanged(BtProfileEnums btProfileEnums, boolean b) {
        LogUtils.d(TAG, "onProfileServiceConnectChanged() called with: btProfileEnums = [" + btProfileEnums + "], b = [" + b + "]");
    }

    @Override
    public void onProfilesConnectChanged(CachedBluetoothDevice cachedBluetoothDevice, int i, String s) {
        LogUtils.d(TAG, "onProfilesConnectChanged() called with: cachedBluetoothDevice = [" + cachedBluetoothDevice + "], i = [" + i + "], s = [" + s + "]");
        updateScanDevices(cachedBluetoothDevice);
        mOnBtTypeListener.onBtType();
    }

    @Override
    public void onPairingListener(CachedBluetoothDevice cachedBluetoothDevice, String s, int i) {

    }

    @Override
    public void onStartPairing(CachedBluetoothDevice cachedBluetoothDevice) {
        LogUtils.d(TAG, "onStartPairing() called with: cachedBluetoothDevice = [" + cachedBluetoothDevice + "]");
    }

    @Override
    public void onPairingConfirmation(CachedBluetoothDevice cachedBluetoothDevice) {
        LogUtils.d(TAG, "onPairingConfirmation() called with: cachedBluetoothDevice = [" + cachedBluetoothDevice + "]");
    }

    private final List<OnBTStateListener> mOnBTStateListenerList = new ArrayList<>();
    private OnBtEnableListener mOnBtEnableListener;

    private OnBtTypeListener mOnBtTypeListener;

    public void registerBTStateListener(OnBTStateListener onBTStateListener){
        mOnBTStateListenerList.add(onBTStateListener);
    }

    public void unregisterBTStateListener(OnBTStateListener onBTStateListener){
        mOnBTStateListenerList.remove(onBTStateListener);
    }

    public void listenBtEnableChanged(OnBtEnableListener onBtEnableListener) {
        mOnBtEnableListener = onBtEnableListener;
    }

    public void listenBtTypeChanged(OnBtTypeListener OnBtTypeListener) {
        mOnBtTypeListener = OnBtTypeListener;
    }

    public interface OnBTStateListener {
        void onBtState(SwitchStateEnum switchStateEnum);
        void onBtName(String name);
        void onScanDevices(List<CachedBluetoothDevice> scanDevices);

        void onScanStateChanged(boolean start);
    }

    public interface OnBtEnableListener {
        void onBtEnable(boolean enable);
    }

    public interface OnBtTypeListener {
        void onBtType();
    }


    public int BTDeviceType() {
        List<CachedBluetoothDevice> pairedBtDevices = bluetoothController.getPairedBtDevices();
        Log.d(TAG, "init: showDevices " + pairedBtDevices.size());
        int type=0;
        if(pairedBtDevices.size() == 0){
          return type;
        }
        ArrayList<Integer> typeArray=new ArrayList<Integer>();
        for (CachedBluetoothDevice pairedBtDevice : pairedBtDevices) {
            boolean isConnectedA2dp = pairedBtDevice.getConnectState(BtProfileEnums.A2DP_SINK) == BTConstants.BluetoothAdapter.STATE_CONNECTED;
            boolean isConnectedHfp = pairedBtDevice.getConnectState(BtProfileEnums.HFP_CLIENT) == BTConstants.BluetoothAdapter.STATE_CONNECTED;
            boolean isConnectedHid = false; // Game
            if(isConnectedA2dp&&isConnectedHfp){
                    type=1;
                    typeArray.add(type);
                    break;
            }else if(isConnectedA2dp){
                    type=2;
                   typeArray.add(type);
            }else if(isConnectedHfp){
                    type=3;
                   typeArray.add(type);
            }else{
                type=0;
            }
        }

        if(typeArray.contains(2)&&typeArray.contains(3)||typeArray.contains(1)){
            type=1;
        }else if(typeArray.contains(2)&&!typeArray.contains(3)){
            type=2;
        }else if(!typeArray.contains(2)&&typeArray.contains(3)){
            type=3;
        }else{
            type=0;
        }
        return type;

    }

}
